/*	Main.cpp
	Copyright 2012 Nico Marrero
	This file is part of SCRNOBS.

    SCRNOBS is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    SCRNOBS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with SCRNOBS.  If not, see <http://www.gnu.org/licenses/>.
*/

#define VERSION "0.5"
#define DEFAULT_DATA_FILE "ObservationData.xml"

#ifndef NDEBUG
	#pragma comment(lib, "wxmsw29ud_core.lib")
	#pragma comment(lib, "wxmsw29ud_adv.lib")
	#pragma comment(lib, "wxmsw29ud_aui.lib")
	#pragma comment(lib, "wxbase29ud.lib")
	#pragma comment(lib, "wxbase29ud_xml.lib")
	#pragma comment(lib, "wxregexud.lib")
	#pragma comment(lib, "wxexpatd.lib")
	#pragma comment(lib, "wxzlibd.lib")
	#pragma comment(lib, "wxjpegd.lib")
	#pragma comment(lib, "wxtiffd.lib")
	#pragma comment(lib, "wxpngd.lib")

#else
	#pragma comment(lib, "wxmsw29u_core.lib")
	#pragma comment(lib, "wxmsw29u_adv.lib")
	#pragma comment(lib, "wxmsw29u_aui.lib")
	#pragma comment(lib, "wxbase29u.lib")
	#pragma comment(lib, "wxbase29u_xml.lib")
	#pragma comment(lib, "wxregexu.lib")
	#pragma comment(lib, "wxexpat.lib")
	#pragma comment(lib, "wxzlib.lib")
	#pragma comment(lib, "wxjpeg.lib")
	#pragma comment(lib, "wxtiff.lib")
	#pragma comment(lib, "wxpng.lib")
#endif

#pragma comment(lib,"comctl32.lib")
#pragma comment(lib,"rpcrt4.lib")

#include <wx/wx.h>
#include <wx/aui/aui.h>
#include <wx/artprov.h>
#include <wx/aboutdlg.h>
#include <wx/generic/aboutdlgg.h>
#include <wx/config.h>
#include <wx/cmdline.h>
#include <wx/docview.h>
#include <wx/wfstream.h>
#include <wx/busyinfo.h>

#include "ObservationData.h"

#ifndef NDEBUG
#pragma comment(lib,"wxExposured.lib")
#else
#pragma comment(lib,"wxExposure.lib")
#endif

enum {ID_DATALIST = wxID_HIGHEST + 1, ID_DATAPANEL, MENUID_EXPORTCSV, MENUID_EXPORTSCRNOBS};

class ObservationMainFrame;

class SaveFunctor
{
public:
	SaveFunctor(wxWindowID SaveType, ObservationMainFrame *Frame, wxString Filename = wxEmptyString):SaveType(SaveType),Frame(Frame),Filename(Filename){}

	void operator()();
private:
	ObservationMainFrame *Frame;
	wxString Filename;
	wxWindowID SaveType;
};

class ObservationMainFrame: public wxFrame, virtual public Exposure
{
public:
	ObservationMainFrame():wxFrame(NULL,wxID_ANY,wxString("Meteorological Observation Data ") + VERSION,wxDefaultPosition, wxSize(1200,600),
		wxBORDER_THEME | wxCLIP_CHILDREN | wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxRESIZE_BORDER | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX),
		m_DataList(NULL),m_DataPanel(NULL), m_Config("SCRNOBS")
	{

		//Menu stuff
		this->CreateMenu();

		this->m_DataList = new wxExposurePanel(this,this,ID_DATALIST);
		this->m_DataPanel = new wxExposurePanel(this,NULL,ID_DATAPANEL);

		//Tell the aui manager to manage this window
		this->m_AuiManager.SetManagedWindow(this);

		//Layout
		this->m_AuiManager.AddPane(this->m_DataList,wxAuiPaneInfo().Name("DataList").Caption("Observation Data List").Left().Position(0).Row(0).CloseButton(false).TopDockable(false).BottomDockable(false).BestSize(280,500));
		this->m_AuiManager.AddPane(this->m_DataPanel,wxAuiPaneInfo().Name("DataPanel").Caption("Observation Data").Center().Position(0).Row(1).CloseButton(false).TopDockable(false).BottomDockable(false).BestSize(736,500));
		this->m_AuiManager.Update();
		this->m_DefaultPerspective = this->m_AuiManager.SavePerspective();
		//this->m_AuiManager.LoadPerspective(this->m_Config.Read("AUIManager/Perspective",wxEmptyString));
	}
	~ObservationMainFrame(){this->CommitInterfaces(); this->m_Config.Write("AUIManager/Perspective",this->m_AuiManager.SavePerspective()); this->m_AuiManager.UnInit();}

	void SaveXML(wxString Filename = wxEmptyString)
	{
		if (Filename.IsEmpty())
		{
			Filename = wxFileSelector("Select save file:",wxEmptyString,wxEmptyString,"XML Files|*.xml","XML Files (*.xml)|*.xml|All Files (*.*)|*.*",wxFD_SAVE|wxFD_OVERWRITE_PROMPT,this);
			if (Filename.IsEmpty()){return;}
		}
		wxXmlDocument SaveFile;
		wxXmlNode *DataNode = new wxXmlNode(wxXML_ELEMENT_NODE, "SCRNOBS");
		ObservationData::SaveAllDataXML(DataNode);
		wxBusyInfo wait("Writing XML file...");
		SaveFile.SetRoot(DataNode);
		SaveFile.Save(Filename);
	}
	void LoadXML(wxString Filename = wxEmptyString, bool LoadSilently = false)
	{
		if (Filename.IsEmpty())
		{
			Filename = wxFileSelector("Select file to load:",wxEmptyString,wxEmptyString,"XML Files|*.xml","XML Files (*.xml)|*.xml|All Files (*.*)|*.*",wxFD_OPEN,this);
			if (Filename.IsEmpty()){return;}
		}
		wxXmlDocument Data;
		bool LoadSuccess = true;
		{
			wxLogNull logno;
			if (!Data.Load(Filename))
			{
				if (!LoadSilently){wxMessageBox("Error loading file '" + Filename + "'.");}

					LoadSuccess = false;
			}
			if (LoadSuccess && Data.GetRoot()->GetName() != "SCRNOBS")
			{
				if (!LoadSilently){wxMessageBox("Error loading file '" + Filename + "'. This file does not appear to be in the SCRNOBS XML format."); }
				LoadSuccess = false;
			}
		}
		
		
		if (LoadSuccess)
		{
			LoadSuccess &= ObservationData::LoadAllDataXML(Data.GetRoot()->GetChildren());
		}
		
		if (LoadSuccess)
		{
			wxBusyInfo wait("Processing loaded data...");
			this->SetCurrentData(ObservationData::FindDataByIndex(0));
			ExposureInterface::UpdateAllInterfaces();
			this->SendSizeEvent();
		}
	}
	void ExportCSV(wxString Filename = wxEmptyString)
	{
		if (Filename.IsEmpty())
		{
			Filename = wxFileSelector("Select export file:",wxEmptyString,wxEmptyString,"CSV Files|*.csv","CSV Files (*.csv)|*.csv|All Files (*.*)|*.*",wxFD_SAVE|wxFD_OVERWRITE_PROMPT,this);
			if (Filename.IsEmpty()){return;}
		}
		wxFileOutputStream OutputStream(Filename); if (!OutputStream.IsOk()){return;}
		wxTextOutputStream Stream(OutputStream);

		ObservationData::ExportAllDataCSV(Stream);
		wxBusyInfo wait("Writing CSV file...",this);
	}
	void ExportSCRNOBS(wxString Filename = wxEmptyString)
	{
		if (Filename.IsEmpty())
		{
			Filename = wxFileSelector("Select export file:",wxEmptyString,wxEmptyString,"SCRNOBS Files|*.OBS","SCRNOBS Files (*.OBS)|*.OBS|All Files (*.*)|*.*",wxFD_SAVE|wxFD_OVERWRITE_PROMPT,this);
			if (Filename.IsEmpty()){return;}
		}
		wxFileOutputStream OutputStream(Filename); if (!OutputStream.IsOk()){return;}
		wxTextOutputStream Stream(OutputStream);

		ObservationData::ExportAllDataSCRNOBS(Stream);
		wxBusyInfo wait("Writing SCRNOBS file...",this);
	}
	int GetCurrentData()
	{
		if (this->m_DataList)
		{
			ObservationData *Obj = dynamic_cast<ObservationData*>(this->m_DataPanel->GetObject());
			if (Obj)
			{
				return(ObservationData::FindIndex(Obj));
			}
		}
		return(wxNOT_FOUND);
	}
	void SetCurrentData(int NewDataIndex)
	{
		ObservationData *obj = ObservationData::FindDataByIndex(NewDataIndex); 
		this->SetCurrentData(obj);
	}
	void SetCurrentData(ObservationData *obj)
	{
		if(obj)
		{
			this->m_DataPanel->ChangeObject(obj);
			this->SendSizeEvent();
		}
	}
	void NewObservation()
	{
		this->m_DataPanel->CommitInterface();
		this->m_DataList->UpdateInterface();
		ObservationData *NewData = new ObservationData();
		this->m_DataPanel->ChangeObject(NewData);
		this->m_DataPanel->SendSizeEvent();
	}
	void CreateMenu()
	{
		wxMenuItem *MenuItem = NULL;
		wxMenu *FileMenu = new wxMenu();
		//MenuItem = new wxMenuItem(FileMenu,wxID_NEW); MenuItem->SetBitmap(wxArtProvider::GetBitmap(wxART_NEW)); FileMenu->Append(MenuItem);
		MenuItem = new wxMenuItem(FileMenu,wxID_OPEN,"L&oad\tCtrl+O"); MenuItem->SetBitmap(wxArtProvider::GetBitmap(wxART_FILE_OPEN)); FileMenu->Append(MenuItem);
		MenuItem = new wxMenuItem(FileMenu,wxID_SAVE); MenuItem->SetBitmap(wxArtProvider::GetBitmap(wxART_FILE_SAVE)); FileMenu->Append(MenuItem);
		MenuItem = new wxMenuItem(FileMenu,wxID_SAVEAS); MenuItem->SetBitmap(wxArtProvider::GetBitmap(wxART_FILE_SAVE_AS)); FileMenu->Append(MenuItem);
		FileMenu->AppendSeparator();
			wxMenu *ExportMenu = new wxMenu();
			ExportMenu->Append(MENUID_EXPORTCSV,"To Excel","Exports all current data into a csv file that can be opened in Excel");
			ExportMenu->Append(MENUID_EXPORTSCRNOBS,"To SCRNOBS","Exports all current data into a SCRNOBS text file");
		FileMenu->AppendSubMenu(ExportMenu, "Export", "Export current data in a format other than XML");
		FileMenu->AppendSeparator();
		MenuItem = new wxMenuItem(FileMenu,wxID_EXIT,"E&xit\tCtrl+X"); MenuItem->SetBitmap(wxArtProvider::GetBitmap(wxART_QUIT)); FileMenu->Append(MenuItem);
		
		wxMenuBar *Menu = this->GetMenuBar();
			wxMenu *HelpMenu = new wxMenu();
				MenuItem = new wxMenuItem(HelpMenu,wxID_ABOUT); MenuItem->SetBitmap(wxArtProvider::GetBitmap(wxART_HELP,wxART_MENU)); HelpMenu->Append(MenuItem);
		
			wxMenu *ViewMenu = new wxMenu();
				ViewMenu->Append(wxID_RESET, "Default Layout", "Returns the current layout to the default");

			Menu = new wxMenuBar(); this->SetMenuBar(Menu);
			Menu->Append(FileMenu,"File");
			Menu->Append(ViewMenu,"View");
			Menu->Append(HelpMenu,"Help");
	}
	void CommitInterfaces(void){this->m_DataPanel->CommitInterface();}
protected:
	void OnExportCSV(wxCommandEvent& event){ExposureThread::PostJob(new SaveFunctor(MENUID_EXPORTCSV,this));}
	void OnExportSCRNOBS(wxCommandEvent& event){ExposureThread::PostJob(new SaveFunctor(MENUID_EXPORTSCRNOBS,this));}
	void OnSave(wxCommandEvent& event){ExposureThread::PostJob(new SaveFunctor(wxID_SAVE,this,DEFAULT_DATA_FILE));}	
	void OnSaveAs(wxCommandEvent& event){ExposureThread::PostJob(new SaveFunctor(wxID_SAVE,this));}
	void OnLoad(wxCommandEvent& event){this->LoadXML();}
	void OnDefaultLayout(wxCommandEvent& event){this->m_AuiManager.LoadPerspective(this->m_DefaultPerspective);}
	void OnExit(wxCommandEvent& event)
	{
		this->Close();
	}
	void OnClose(wxCloseEvent& event)
	{
		this->Destroy();
	}
	void OnAbout(wxCommandEvent& event)
	{
		wxAboutDialogInfo info;
		info.SetName("SCRNOBS");
		info.SetVersion(VERSION);
		info.SetCopyright(wxString::Format("Copyright %d Nico Marrero",wxDateTime::GetCurrentYear()));
		info.SetDescription("SCRNOBS takes data from meteorological observation cards and stores it electronically.\n" \
			"SCRNOBS Export format taken from Jerry Blechman's original SCRNOBS Fortran program.");
		wxGenericAboutBox(info);
	}
	wxExposurePanel *m_DataPanel;
	wxExposurePanel *m_DataList;
	wxAuiManager m_AuiManager;
	wxConfig m_Config;
	wxString m_DefaultPerspective;
	DECLARE_EXPOSURE_TABLE();
	DECLARE_EVENT_TABLE();
};

BEGIN_EVENT_TABLE(ObservationMainFrame,wxFrame)
	//EVT_MENU(wxID_NEW, ObservationMainFrame::OnNew)
	EVT_MENU(MENUID_EXPORTCSV, ObservationMainFrame::OnExportCSV)
	EVT_MENU(MENUID_EXPORTSCRNOBS, ObservationMainFrame::OnExportSCRNOBS)
	EVT_MENU(wxID_SAVE, ObservationMainFrame::OnSave)
	EVT_MENU(wxID_SAVEAS, ObservationMainFrame::OnSaveAs)
	EVT_MENU(wxID_OPEN, ObservationMainFrame::OnLoad)
	//EVT_MENU(MENUID_EXPORT, ObservationMainFrame::OnExport)
	EVT_MENU(wxID_EXIT, ObservationMainFrame::OnExit)
	EVT_CLOSE(ObservationMainFrame::OnClose)
	EVT_MENU(wxID_ABOUT, ObservationMainFrame::OnAbout)
	EVT_MENU(wxID_RESET,ObservationMainFrame::OnDefaultLayout)
END_EVENT_TABLE()

BEGIN_EXPOSURE_TABLE(ObservationMainFrame,"The list of data")
	EXPOSE_LIST("Data","",ObservationMainFrame::GetCurrentData, &ObservationMainFrame::SetCurrentData,"")->Dynamic(&ObservationData::GetDataChanged,
					&ObservationData::GetDataCount,&ObservationData::GetDataIndices,&ObservationData::GetDataIDs,NULL)->AlignCenter()->Sorted()
	EXPOSURE_ROW()
	EXPOSURE_GROUP()
		EXPOSE_BUTTON("AddData","New Observation",&ObservationMainFrame::NewObservation,"Adds a new observation")
	EXPOSURE_END_GROUP()
END_EXPOSURE_TABLE()



void SaveFunctor::operator()()
{
	Frame->CommitInterfaces();
	switch(SaveType)
	{
	case(MENUID_EXPORTCSV):{Frame->ExportCSV(Filename);break;}
	case(MENUID_EXPORTSCRNOBS):{Frame->ExportSCRNOBS(Filename);break;}
	default:{Frame->SaveXML(Filename);break;}
	};
	delete this;
}




static const wxCmdLineEntryDesc g_cmdLineDesc[] =
{
	{wxCMD_LINE_PARAM, NULL, NULL, "input file", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL},
	{wxCMD_LINE_NONE}
};
class ObservationApp : public wxApp {public: bool OnInit();};
DECLARE_APP(ObservationApp);
IMPLEMENT_APP(ObservationApp)
bool ObservationApp::OnInit()
{
	wxString FilenameToOpen;

	//Parse command line
	wxCmdLineParser cmdParser(g_cmdLineDesc, argc, argv);
	cmdParser.Parse(false);
	if (cmdParser.GetParamCount() > 0)
	{
		wxFileName fName(cmdParser.GetParam(0));
		fName.Normalize(wxPATH_NORM_LONG|wxPATH_NORM_DOTS|wxPATH_NORM_TILDE|wxPATH_NORM_ABSOLUTE);
		FilenameToOpen = fName.GetFullPath();
	}
	//Create main app window
	::wxInitAllImageHandlers();
	ObservationMainFrame *frame = new ObservationMainFrame();
	//wxIcon icon(ASCCIcon_xpm);
	//frame->SetIcon(icon);
	frame->Show(true);
	frame->LoadXML(DEFAULT_DATA_FILE,true);
	//if (!FilenameToOpen.IsEmpty()){frame->Load(FilenameToOpen);}
	return(true);
}
